package com.sondon.dev_soceket.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.io.IOException;
import java.util.List;

import com.sondon.dev_soceket.model.TCPEntity;
import com.sondon.dev_soceket.tcp.util.CodeUtil;

/**
 * 
 * @Project : Java_C_Socket_Maven
 * @Package : com.sondon.netty
 * @Class : ServerEntityDecoder.java
 * @Company 广州讯动网络科技有限公司
 * @Author : 蔡文锋
 * @DateTime：2015年4月22日 下午5:53:06
 * @Blog：http://blog.csdn.net/caiwenfeng_for_23
 * @Description : {消息解码类}
 */
public class ServerEntityDecoder extends ByteToMessageDecoder {
	// private static final int BUFFER_SIZE = 1024;// 缓存大小
	byte[] recvBuf = null;// 接收消息的缓存
	private final static String HEAD = "4A79";// 包头标志
	int count = 0;// 接收消息的总大小
	byte[] byteMerger = new byte[0];// 接收消息byte数组合并
	int cut_count = 0;// 裁剪值 0:不裁剪 1:裁剪
	boolean DeCode_Success = true; //
	int recvMsgSize = 0;// byte数组接收消息的大小

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf bb,
			List<Object> out) {
		recvMsgSize = bb.readableBytes();
		recvBuf = new byte[recvMsgSize];
		bb.readBytes(recvBuf);
		count = recvMsgSize + count;
		// 合并数组
		byteMerger = CodeUtil.byteMerger(byteMerger, recvBuf, recvMsgSize);
		if (count < 24) {
			return;
		}
		// 判断是否已经读完;判断数据是否完整
		if (count >= 24) {
			// byte[]数组转为16进制字符串
			String recvData = CodeUtil.printHexString(byteMerger, count);
			System.out.println("recvMsgSize  :" + recvMsgSize + "  recvBuf :"+ recvData);
			// 清理字符串的空格
			recvData = recvData.replace(" ", "");
			// 解析协议
			byteMerger = Solve_Stick_Package(recvData, out, cut_count,
					DeCode_Success);
			// byteMerger = DecodeStrData(recvData, out, cut_count,
			// DeCode_Success);
			count = byteMerger.length;
			DeCode_Success = true;
			cut_count = 0;
		}
		// 清空recvBuf
		recvBuf = null;
	}

	/**
	 * @Author 蔡文锋
	 * @Data_Time 2015年4月2日 上午10:21:23
	 * @Description {字符串形式解析包协议}
	 * @param data
	 * @return
	 * @throws IOException
	 */
	public byte[] DecodeStrData(String data, List<Object> out, int cut_count,
			boolean DeCode_Success) {

		// 协议格式：Entity类
		TCPEntity entity = new TCPEntity();
		// 分配HEAD字段
		entity.setHEAD(data.substring(0, 4));
		// 检查包头标志： HEAD
		if (data.length() > 48 && HEAD.equals(entity.getHEAD().toUpperCase())) {
			entity.setPACKNO(data.substring(4, 8));
			entity.setSADR(data.substring(8, 16));
			entity.setDADR(data.substring(16, 24));
			entity.setPORT(data.substring(24, 32));
			entity.setFLAG(data.substring(32, 36));
			entity.setCMD(data.substring(36, 40));
			entity.setLEN(data.substring(40, 44));
			// 索引
			int index = 44 + 4 + 2 * CodeUtil.HexStringToInt(entity.getLEN());
			// 判断索引是否超出字符串长度
			if (index <= data.length()) {
				entity.setDATA(data.substring(44, index - 4));
				entity.setCRC16(data.substring(index - 4, index));

				// CRC16校验
				byte[] crc16_data = CodeUtil.hexStringToBytes(entity.getSADR()
						+ entity.getDADR() + entity.getPORT()
						+ entity.getFLAG() + entity.getCMD() + entity.getLEN()
						+ entity.getDATA());
				String crc16 = CodeUtil.CRC16Table(crc16_data);
				crc16 = crc16.substring(0, 4);
				// CRC校验，判断数据是否完整
				if (crc16.equals(entity.getCRC16())) {
					// j校验通过，传递Entity
					out.add(entity);

					// 裁剪一个完整的包数据
					// System.out.println("裁剪一个完整包前的data   :"+data);
					data = data.substring(index, data.length());
					// System.out.println("裁剪一个完整包后的data   :" + data);
					cut_count = 0;
					// 数据完整并且校验通过
					DeCode_Success = true;
				} else {
					// 数据长度足够，但CRC校验不通过
					DeCode_Success = false;
				}
			} else {
				// 数据长度不够
				DeCode_Success = false;
			}
		} else {
			// 数据包标志格式不对
			DeCode_Success = false;
		}

		// System.out.println("DeCode_Success   :"+DeCode_Success);
		return Solve_Stick_Package(data, out, cut_count, DeCode_Success);
	}

	/**
	 * @Author 蔡文锋
	 * @Data_Time 2015年4月2日 上午10:21:23
	 * @Description {解决粘包，包不完整等问题}
	 * @param data
	 * @param out
	 * @return
	 * @throws IOException
	 */
	public byte[] Solve_Stick_Package(String data, List<Object> out,
			int cut_count, boolean DeCode_Success) {
		// System.out.println("包数据：  "+data);
		int HEAD_COUNT = CodeUtil.getContain_StrCount(HEAD, data);
		// System.out.println("HEAD_COUNT   :" + HEAD_COUNT);
		// 判断数据长度并且包含包头标志
		if (data.length() > 48 && HEAD_COUNT > 1) {
			data = data.substring(data.indexOf(HEAD) + 4 * cut_count,
					data.length());
			cut_count = 1;
			// System.out.println("第二次裁剪后的data  ：" + data);
			return DecodeStrData(data, out, cut_count, DeCode_Success);
		} else if (data.length() > 0 && HEAD_COUNT < 1) {
			// data中没有包头标志，说明不是一个完整包，丢弃
			data = null;
			// System.out.println("data中没有包头标志，说明不是一个完整包，丢弃data");
			return new byte[0];
		} else if (HEAD_COUNT > 0) {// 临界状态，只有一个包头标志，但数据不全等
			if (data.length() < 48 || !DeCode_Success) {
				// data中包含包头标志，但数据不完全
				// System.out.println("data中包含包头标志，但数据不完全    data ： " + data);
				return CodeUtil.hexStringToBytes(data);
			} else {
				// data中包含包头标志，但不肯定数据是否完全，不完全时 DeCode_Success标志为：true
				// System.out.println("data中包含包头标志，但不肯定数据是否完全  data :  "+data);
				return DecodeStrData(data, out, cut_count, DeCode_Success);
			}
		}
		return new byte[0];
	}
}
